/*
 * SPDX-FileCopyrightText: 2021-2024 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdint.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/i2s_std.h"
#include "driver/gpio.h"
#include "esp_check.h"
#include "sdkconfig.h"

#include "format_wav.h"
#include "i2s/format_wav.h"
#include<string.h> 




#define EXAMPLE_STD_BCLK_IO        GPIO_NUM_14     // I2S bit clock io number
#define EXAMPLE_STD_WS_IO          GPIO_NUM_13     // I2S word select io number
#define EXAMPLE_STD_DOUT_IO        GPIO_NUM_45     // I2S data out io number
#define EXAMPLE_STD_DIN_IO         GPIO_NUM_12     // I2S data in io number


#define EXAMPLE_BUFF_SIZE               7200

static i2s_chan_handle_t                tx_chan;        // I2S tx channel handler
static i2s_chan_handle_t                rx_chan;        // I2S rx channel handler

static void i2s_example_read_task(void *args)
{
    uint8_t *r_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
    assert(r_buf); // Check if r_buf allocation success
    size_t r_bytes = 0;

    /* Enable the RX channel */
    //ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));

    /* ATTENTION: The print and delay in the read task only for monitoring the data by human,
     * Normally there shouldn't be any delays to ensure a short polling time,
     * Otherwise the dma buffer will overflow and lead to the data lost */
    while (1) {

         printf("start i2s Read Task\n");
        /* Read i2s data */
        if (i2s_channel_read(rx_chan, r_buf, EXAMPLE_BUFF_SIZE, &r_bytes, portMAX_DELAY) == ESP_OK) {
            printf("Read Task: i2s read %d bytes\n-----------------------------------\n", r_bytes);
            printf("[0] %x [1] %x [2] %x [3] %x\n[4] %x [5] %x [6] %x [7] %x\n\n",
                   r_buf[0], r_buf[1], r_buf[2], r_buf[3], r_buf[4], r_buf[5], r_buf[6], r_buf[7]);
        } else {
            printf("Read Task: i2s read failed\n");
        }
        //vTaskDelay(pdMS_TO_TICKS(200));
    }
    free(r_buf);
    vTaskDelete(NULL);
}

#define INT16_MAX 32768
esp_err_t bsp_i2s_read_data(int16_t *buffer, int buffer_len,size_t* r_bytes){
    esp_err_t ret = ESP_OK;
    
    int32_t bit32_buffer[160];
    ret = i2s_channel_read(rx_chan, bit32_buffer, 160*4, r_bytes, portMAX_DELAY);

    int samples = *r_bytes/4;

    //printf("samples:%d  buffer_len:%d \n",samples,buffer_len);

    for(int i = 0;i<samples;i++){
        int32_t value = bit32_buffer[i]>>14;
        buffer[i] =  (value > INT16_MAX) ? INT16_MAX : (value < -INT16_MAX) ? -INT16_MAX : (int16_t)value;
    }

    return ret;
}


static void i2s_example_write_task(void *args)
{
    // uint8_t *w_buf = (uint8_t *)calloc(1, EXAMPLE_BUFF_SIZE);
    // assert(w_buf); // Check if w_buf allocation success

    // /* Assign w_buf */
    // for (int i = 0; i < EXAMPLE_BUFF_SIZE; i += 8) {
    //     w_buf[i]     = 0x12;
    //     w_buf[i + 1] = 0x34;
    //     w_buf[i + 2] = 0x56;
    //     w_buf[i + 3] = 0x78;
    //     w_buf[i + 4] = 0x9A;
    //     w_buf[i + 5] = 0xBC;
    //     w_buf[i + 6] = 0xDE;
    //     w_buf[i + 7] = 0xF0;
    // }

    // size_t w_bytes = EXAMPLE_BUFF_SIZE;

    // /* (Optional) Preload the data before enabling the TX channel, so that the valid data can be transmitted immediately */
    // while (w_bytes == EXAMPLE_BUFF_SIZE) {
    //     /* Here we load the target buffer repeatedly, until all the DMA buffers are preloaded */
    //     ESP_ERROR_CHECK(i2s_channel_preload_data(tx_chan, w_buf, EXAMPLE_BUFF_SIZE, &w_bytes));
    // }

 



    
    
    while (1) {
        char* path = "/sdcard/muyu.wav";
        //char* path = "/sdcard/echo.wav";
        //char* path = "/sdcard/poweron.wav";
        ESP_LOGI("TAG", "Reading file %s", path);
        FILE *f = fopen(path, "rb");
        if (f == NULL) {
            ESP_LOGE("TAG", "Failed to open file for reading");
            return ;
        }
    
        wav_header_t  wav_header;
        fread(&wav_header.descriptor_chunk,sizeof(wav_header.descriptor_chunk),1,f);    
        fread(&wav_header.fmt_chunk,sizeof(wav_header.fmt_chunk),1,f);    

        printf("文件类型: %.4s\r\n", wav_header.descriptor_chunk.chunk_id);
        printf("文件大小: %ld\r\n", wav_header.descriptor_chunk.chunk_size);

        // 读取fmt块
        
        printf("音频格式: %d\n", wav_header.fmt_chunk.audio_format);
        printf("通道数: %d\n", wav_header.fmt_chunk.num_of_channels);
        printf("采样率: %ld\n", wav_header.fmt_chunk.sample_rate);
        printf("位深: %d\n", wav_header.fmt_chunk.bits_per_sample);

        printf("文件大小: %ld\r\n", wav_header.descriptor_chunk.chunk_size);

        // 读取fmt块
        fread(&wav_header.data_chunk.subchunk_id,sizeof(wav_header.data_chunk.subchunk_id),1,f);
        
        fread(&wav_header.data_chunk.subchunk_size,sizeof(wav_header.data_chunk.subchunk_size),1,f);

        printf("音频数据大小：%ld\n",wav_header.data_chunk.subchunk_size);

        uint8_t data[EXAMPLE_BUFF_SIZE];

        size_t w_bytes = EXAMPLE_BUFF_SIZE;
        /* Enable the TX channel */
        ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
        while(!feof(f)){
            memset(data,0,sizeof(data));
            size_t length = fread(data,sizeof(data),1,f);
        

            if (i2s_channel_write(tx_chan, data, EXAMPLE_BUFF_SIZE, &w_bytes, 1000) == ESP_OK) {
                printf("Write Task: i2s write %d bytes\n", w_bytes);
            } else {
                printf("Write Task: i2s write failed\n");
            }
        }
        ESP_ERROR_CHECK(i2s_channel_disable(tx_chan));
        fclose(f);



        vTaskDelay(pdMS_TO_TICKS(500));
    }
   
    vTaskDelete(NULL);
}


void bsp_i2s_init_std_duplex(void)
{
    /* Setp 1: Determine the I2S channel configuration and allocate both channels
     * The default configuration can be generated by the helper macro,
     * it only requires the I2S controller id and I2S role */
    //i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
    //ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan));


    i2s_chan_config_t chan_cfg = {
        .id = I2S_NUM_0,
        .role = I2S_ROLE_MASTER,
        .dma_desc_num = 6,
        .dma_frame_num = 240*3,
        .auto_clear_after_cb = false,
        .auto_clear_before_cb = false,
        .intr_priority = 0,
    };
    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, &tx_chan, &rx_chan));




    /* Step 2: Setting the configurations of standard mode, and initialize rx & tx channels
     * The slot configuration and clock configuration can be generated by the macros
     * These two helper macros is defined in 'i2s_std.h' which can only be used in STD mode.
     * They can help to specify the slot and clock configurations for initialization or re-configuring */
    i2s_std_config_t std_cfg = {
        .clk_cfg  = {
            .sample_rate_hz = 16000,
            .clk_src = I2S_CLK_SRC_DEFAULT,
            .ext_clk_freq_hz = 0,
            .mclk_multiple = I2S_MCLK_MULTIPLE_256
        },
        .slot_cfg = {
            .data_bit_width = I2S_DATA_BIT_WIDTH_32BIT,
            .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
            .slot_mode = I2S_SLOT_MODE_MONO,
            .slot_mask = I2S_STD_SLOT_LEFT,
            .ws_width = I2S_DATA_BIT_WIDTH_32BIT,
            .ws_pol = false,
            .bit_shift = true,
            .left_align = true,
            .big_endian = false,
            .bit_order_lsb = false
        },
        .gpio_cfg = {
            .mclk = I2S_GPIO_UNUSED,    // some codecs may require mclk signal, this example doesn't need it
            .bclk = EXAMPLE_STD_BCLK_IO,
            .ws   = EXAMPLE_STD_WS_IO,
            .dout = EXAMPLE_STD_DOUT_IO,
            .din  = EXAMPLE_STD_DIN_IO, // In duplex mode, bind output and input to a same gpio can loopback internally
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv   = false,
            },
        },
    };
    /* Initialize the channels */
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(tx_chan, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
    ESP_LOGI("TAG", "Duplex channels created");
}


void example_audio_test(void)
{

    bsp_i2s_init_std_duplex();

    xTaskCreate(i2s_example_read_task, "i2s_example_read_task", 4096*2, NULL, 5, NULL);
    //xTaskCreate(i2s_example_write_task, "i2s_example_write_task", 9012, NULL, 5, NULL);
}
